package cn.xlbweb.cli.shiro;

import cn.xlbweb.cli.config.CliProperties;
import cn.xlbweb.cli.util.CliUtils;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author: bobi
 * @date: 2019-09-16 20:21
 * @description:
 */
@Configuration
public class ShiroConfig {

    @Autowired
    private CliProperties cliProperties;

    @Bean
    public CredentialsMatcher credentialsMatcher() {
        CliCredentialsMatcher cliCredentialsMatcher = new CliCredentialsMatcher(ehCacheManager());
        // 密码加密算法
        cliCredentialsMatcher.setHashAlgorithmName(cliProperties.getAlgorithmName());
        // 密码加密hash次数
        cliCredentialsMatcher.setHashIterations(cliProperties.getHashIterations());
        // 登录次数
        cliCredentialsMatcher.setMaxRetryNum(5);
        // 是否使用hex编码
        cliCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return cliCredentialsMatcher;
    }

    @Bean
    public CliRealm cliRealm() {
        CliRealm cliRealm = new CliRealm();
        // 注入密码匹配器
        cliRealm.setCredentialsMatcher(credentialsMatcher());
        // 开启认证缓存
        cliRealm.setAuthenticationCachingEnabled(true);
        cliRealm.setAuthenticationCacheName("authenticationCache");
        // 开启授权缓存
        cliRealm.setAuthorizationCachingEnabled(true);
        cliRealm.setAuthorizationCacheName("authorizationCache");
        return cliRealm;
    }

    @Bean
    public CliSessionManager cliSessionManager() {
        return new CliSessionManager();
    }

    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManagerConfigFile("classpath:config/ehcache.xml");
        return ehCacheManager;
    }

    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 注入自定义Realm
        securityManager.setRealm(cliRealm());
        // 注入自定义session管理器
        securityManager.setSessionManager(cliSessionManager());
        // 注入EhCache缓存
        securityManager.setCacheManager(ehCacheManager());
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 注入安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager());

        // 注入自定义认证过滤器
        Map<String, Filter> shiroFilter = shiroFilterFactoryBean.getFilters();
        shiroFilter.put("authc", new CliAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(shiroFilter);

        // 注入自定义过滤规则
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 免认证URI
        List<String> excludeUriList = CliUtils.strToStringList(cliProperties.getExcludeUri());
        for (String excludeUri : excludeUriList) {
            filterChainDefinitionMap.put(excludeUri, "anon");
        }
        // 其它请求都需要认证
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
    }
}
